//
//  JSContext.m
//  IV8
//
//  Created by Joseph Gentle on 6/05/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "JSContext.h"

// Extracts an NSString from a V8 Utf8Value.
NSString* ToNSString(const v8::String::Utf8Value& value) {
	const char *cstr = *value ? *value : "<string conversion failed>";
	return [NSString stringWithUTF8String:cstr];
}

NSString *ExceptionToNSString(v8::TryCatch *try_catch) {
	v8::HandleScope handle_scope;
	v8::String::Utf8Value exception(try_catch->Exception());
	NSString *exception_string = ToNSString(exception);
	v8::Handle<v8::Message> message = try_catch->Message();
	if (message.IsEmpty()) {
		return exception_string;
	}
	
	v8::String::Utf8Value filename(message->GetScriptResourceName());
	NSMutableString *result = [NSMutableString stringWithString:@"  "];
    int start = message->GetStartColumn();
    for (int i = 0; i < start; i++) {
		[result appendString:@" "];
    }
    int end = message->GetEndColumn();
	if (end == start) end = start + 1;
    for (int i = start; i < end; i++) {
		[result appendString:@"^"];
    }
    [result appendString:@"\n"];
	[result appendString:exception_string];
	//[result appendString:@"\n"];
	return result;
}

@implementation JSContext

- (id)init {
	if (![super init])
		return nil;
	
	context = v8::Context::New();
	return self;
}

- (void)dealloc {
	[super dealloc];
}

- (NSString *)executeString:(NSString *)nsquery {
	v8::Context::Scope scope(context);
	v8::HandleScope handle_scope;
	
	const char *cquery = [nsquery UTF8String];
	v8::Handle<v8::String> query = v8::String::New(cquery);
	
	v8::TryCatch try_catch;
	
	v8::Handle<v8::Script> script
			= v8::Script::Compile(query, v8::String::New("(shell)"));
  
	if (script.IsEmpty()) {
		// Print errors that happened during compilation.
		return ExceptionToNSString(&try_catch);
	} else {
		v8::Handle<v8::Value> result = script->Run();
		if (result.IsEmpty()) {
			// Print errors that happened during execution.
			return ExceptionToNSString(&try_catch);
		} else {
			if (!result->IsUndefined()) {
				// If all went well and the result wasn't undefined then print
				// the returned value.
				v8::String::Utf8Value str(result);
				return ToNSString(str);
			}
			return ExceptionToNSString(&try_catch);
		}
	}		
}
	
@end
